package io.github.wx.common.shiro.kit;

import com.jfinal.aop.Duang;
import com.jfinal.kit.LogKit;
import com.jfinal.plugin.redis.Redis;
import com.xiaoleilu.hutool.util.CollectionUtil;
import io.github.wx.common.shiro.cache.RedisSessionDAO;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.subject.Subject;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Created by jie on 2017/4/9.
 * 在redis 中维护 loginName --》 sessionID --》 session的关系 方便session操作
 * 不建议在SessionDao 直接调用，
 * SecurityUtils 工具类的初始化应该SessionDao操作之后，
 * 否则会出现StackOverflow的异常
 */
public class ShiroSessionKit {
    /**
     * 储存用户session的KEY
     */
    public static final String USER_SESSION = "user_session_";


    /**
     * 添加用户名和SessionID 关系方便操作session
     */
    public static void addSessionRelation() {
        Subject subject = SecurityUtils.getSubject();
        if (subject != null && subject.getPrincipal() != null && subject.getSession() != null) {
            int expire = (int) subject.getSession().getTimeout();
            Redis.use().setex(USER_SESSION + subject.getPrincipal().toString(), expire / 1000, subject.getSession().getId());
        }
    }

    /**
     * 删除用户名和SessionID 关系方便操作session
     *
     * @param username 用户名
     */
    public static void delSessionRelation(String username) {
        Redis.use().del(USER_SESSION + username);
    }

    /**
     * 更新用户名和Session的关系。
     * 解决shiro session过期时间更新
     * 关系不同步的情况，在sessionDao 中调用
     *
     * @param session Session
     */
    public static void updSessionRelation(Session session) {
        if (session != null && session.getId() != null) {
            Set<String> keys = Redis.use().keys(USER_SESSION + "*");
            if (CollectionUtil.isNotEmpty(keys)) {
                for (String key : keys) {
                    Serializable serializable = Redis.use().get(key);
                    if (serializable.equals(session.getId())) {
                        int expire = (int) session.getTimeout();
                        Redis.use().setex(key, expire / 1000, session.getId());
                    }
                }
            }
        }
    }

    /**
     * 获取全部登录的用户信息
     *
     * @return List
     */
    public static List<UserSessionVo> getAllSessionRelation() {
        List<UserSessionVo> userSessionVoList = new ArrayList<UserSessionVo>();
        Set<String> keys = Redis.use().keys(USER_SESSION + "*");
        if (CollectionUtil.isNotEmpty(keys)) {
            for (String key : keys) {
                UserSessionVo vo = new UserSessionVo();
                Serializable serializable = Redis.use().get(key);
                vo.setSessionId(serializable.toString());
                vo.setUsername(key.replace("user_session_",""));
                userSessionVoList.add(vo);
            }
        }
        return userSessionVoList;
    }

    /**
     * 根据用户名删除Session 和 关系映射
     *
     * @param username
     */
    public static void delSession(String username) {
        RedisSessionDAO sessionDAO = Duang.duang(RedisSessionDAO.class);
        //查找sessionID
        Serializable sessionId = Redis.use().get(ShiroSessionKit.USER_SESSION + username);
        if (sessionId != null) {
            try {
                ShiroSessionKit.delSessionRelation(username);
                Session session = sessionDAO.readSession(sessionId);
                sessionDAO.delete(session);
            } catch (UnknownSessionException e) {
                LogKit.debug("强制下线用户异常:" + e.getMessage());
            }
        }
    }
}
